
#include "rtthread.h"
#include "rthw.h"
#include "board.h"


#ifdef RT_USING_FINSH
#define CONSOLE_RX_BUFSZ 16
static uint32_t console_rx_buf[CONSOLE_RX_BUFSZ];
static struct rt_mailbox console_rx_mb;
#endif
static struct rt_semaphore console_tx_sem;
static struct rt_mutex console_mutex;



int ev_console_init(uint32_t baudrate)
{

#ifdef RT_USING_FINSH
    rt_mb_init(&console_rx_mb, "logrx", (void *)console_rx_buf, CONSOLE_RX_BUFSZ, RT_IPC_FLAG_FIFO);
#endif
    rt_sem_init(&console_tx_sem, "logtx", 0, RT_IPC_FLAG_FIFO);
    rt_mutex_init(&console_mutex, "logtx", RT_IPC_FLAG_FIFO);

    driv_console_uart_init(baudrate);
    return 0;
}


/* for finsh */
#ifdef RT_USING_FINSH
char rt_hw_console_getchar(void)
{
    uint32_t data;
    if (rt_mb_recv(&console_rx_mb, (rt_ubase_t *)&data, RT_WAITING_FOREVER) == RT_EOK)
    {
        return (char)data;
    }
    return (char)-1;
}
#endif


void rt_kprintf(const char *format, ...)
{
    static char console_tx_buf[RT_CONSOLEBUF_SIZE * 2];
    va_list args;
    rt_size_t length;

    rt_mutex_take(&console_mutex, RT_WAITING_FOREVER);
    va_start(args, format);
    rt_vsnprintf(&console_tx_buf[RT_CONSOLEBUF_SIZE],
                 RT_CONSOLEBUF_SIZE - 1,
                 format,
                 args
    );
    length = rt_strlen(&console_tx_buf[RT_CONSOLEBUF_SIZE]);
    va_end(args);

    int tx_len = 0;
    for (rt_size_t i = 0; i < length; i ++)
    {
        if (console_tx_buf[i + RT_CONSOLEBUF_SIZE] == '\n')
        {
            console_tx_buf[tx_len ++] = '\r';
        }
        console_tx_buf[tx_len ++] = console_tx_buf[i + RT_CONSOLEBUF_SIZE];
    }
    if (tx_len > 0) {
        driv_console_uart_write((uint8_t *)console_tx_buf, tx_len);
        rt_sem_take(&console_tx_sem, RT_WAITING_FOREVER);
    }
    rt_mutex_release(&console_mutex);
}

void driv_console_uart_tx_cb(void)
{
    rt_interrupt_enter();
    rt_sem_release(&console_tx_sem);
    rt_interrupt_leave();
}

void driv_console_uart_rx_cb(uint8_t c)
{
    rt_interrupt_enter();
    rt_mb_send(&console_rx_mb, (rt_ubase_t)c);
    rt_interrupt_leave();
}
